package com.yunxin.core.application.service.impl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.RandomUtil;
import com.yunxin.common.exception.BusinessException;
import com.yunxin.common.utils.JacksonUtils;
import com.yunxin.core.application.command.contact.SmsMessageCallbackCommand;
import com.yunxin.core.application.service.ContactApplicationGatewayService;
import com.yunxin.core.domain.model.contact.CaptchaLimitSmsCode;
import com.yunxin.core.domain.model.contact.MessageCallback;
import com.yunxin.core.domain.service.contact.impl.SendMessageFactory;
import com.yunxin.core.infra.common.contact.enums.MessageSendStatusEnum;
import com.yunxin.core.infra.common.contact.enums.SendSourceEnum;
import com.yunxin.core.utils.infra.common.constant.CoreResultCode;
import com.yunxin.core.utils.infra.common.constant.RedisConstants;
import com.yunxin.core.utils.infra.utils.DateUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author zero°
 * @since 2023-07-12
 */
@Service
@RequiredArgsConstructor
public class ContactApplicationGatewayServiceImpl implements ContactApplicationGatewayService {

    private static final String SUCCESS_STATUS = "0";

    @Value("${sms.switch}")
    private boolean smsSwitch;

    private final StringRedisTemplate stringRedisTemplate;

    private final SendMessageFactory sendMessageFactory;



    @Override
    public void sendSmsVerificationCode(String taskCode, String phone, String scene, String clientIp) {
        CaptchaLimitSmsCode limitDTO = null;
        String key = RedisConstants.INSTANCE.of(RedisConstants.SMS_CAPTCHA + phone + scene);
        // 获取手机号防刷限制缓存
        ValueOperations<String, String> redisCache = stringRedisTemplate.opsForValue();
        String captchaStr = redisCache.get(key);
        if (CharSequenceUtil.isNotEmpty(captchaStr)) {
            limitDTO = JacksonUtils.X.parse(captchaStr, CaptchaLimitSmsCode.class);
            if (limitDTO != null) {
                if (limitDTO.getCount() > CaptchaLimitSmsCode.TRY_TIMES) {
                    throw new BusinessException(CoreResultCode.VERIFICATION_CODE_TRY_MORE_ERROR_1);
                }
                if (DateUtils.X.getAroundMinute(-1).compareTo(limitDTO.getTime()) <= 0) {
                    throw new BusinessException(CoreResultCode.VERIFICATION_CODE_1_MIN_ERROR);
                }
            }
        }
        String captcha = RandomUtil.randomNumbers(6);
        // 短信验证码保存
        if (limitDTO == null) {
            limitDTO = new CaptchaLimitSmsCode();
            limitDTO.setCount(0);
        }
        limitDTO.setTime(System.currentTimeMillis());
        limitDTO.setCode(captcha);
        if (smsSwitch && "adminLogin".equals(scene)) {
            sendMessageFactory.sendMessage(captcha, taskCode, List.of(phone), clientIp);
        }
        ValueOperations<String, String> value = stringRedisTemplate.opsForValue();
        value.set(key, JacksonUtils.X.format(limitDTO), RedisConstants.REDIS_CAPTCHA_OVER_TIME, TimeUnit.MINUTES);
    }

    @Override
    public boolean verificationSmsCode(String phone, String verificationCode, String scene) {

        //不是crm登录直接true
        if (!"adminLogin".equals(scene)) {
            return Boolean.TRUE;
        }
        //关闭验证码
        if (!smsSwitch) {
            return Boolean.TRUE;
        }
        ValueOperations<String, String> value = stringRedisTemplate.opsForValue();
        String captchaStr = value.get(RedisConstants.INSTANCE.of(RedisConstants.SMS_CAPTCHA + phone + scene ));
        if (captchaStr == null) {
            throw new BusinessException(CoreResultCode.VERIFICATION_CODE_EXPIRE);
        }
        CaptchaLimitSmsCode vo = JacksonUtils.X.parse(captchaStr, CaptchaLimitSmsCode.class);
        if (vo != null && DateUtils.X.getAroundMinute(RedisConstants.CAPTCHA_TIMEOUT).compareTo(vo.getTime()) < 0) {
            if (vo.getCount() > CaptchaLimitSmsCode.TRY_TIMES) {
                throw new BusinessException(CoreResultCode.VERIFICATION_CODE_TRY_MORE_ERROR);
            }
            if (!vo.getCode().equals(verificationCode)) {
                vo.setCount(vo.getCount() + 1);
                throw new BusinessException(CoreResultCode.VERIFICATION_CODE_ERROR);
            }
        } else {
            throw new BusinessException(CoreResultCode.VERIFICATION_CODE_EXPIRE);
        }
        return Boolean.TRUE;
    }

    @Override
    public void smsCallback(List<SmsMessageCallbackCommand> commands) {
        List<MessageCallback> messageCallbacks = commands.stream().map(x -> {
            MessageCallback dto = new MessageCallback();
            dto.setStatus(MessageSendStatusEnum.REACH_FAIL.getStatus());
            if (SUCCESS_STATUS.equalsIgnoreCase(x.getStatus())) {
                dto.setStatus(MessageSendStatusEnum.REACH_SUCCESS.getStatus());
            }
            dto.setStatusDesc(x.getDesc());
            dto.setUid(x.getUid());
            return dto;
        }).toList();
        sendMessageFactory.messageCallback(SendSourceEnum.SMS.getSourceType(), messageCallbacks);
    }
}
